package com.ailanyin.generate.utils;

import com.ailanyin.generate.config.GenerateConfig;
import com.ailanyin.generate.model.ColumnClass;
import com.ailanyin.generate.model.ModelInfo;
import com.google.common.base.CaseFormat;
import freemarker.cache.ClassTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

/**
 * @author ailanyin
 * @version 1.0
 * @since 2022/1/4 0004 下午 14:52
 */
public class GenerateUtil {

    public static void startGenerate(GenerateConfig config) {
        try {

            Configuration cfg = new Configuration(Configuration.VERSION_2_3_30);
            cfg.setTemplateLoader(new ClassTemplateLoader(GenerateUtil.class, "/templates"));
            cfg.setDefaultEncoding(config.getChartSet());
            Connection connection = MysqlUtil.connectionMysql("jdbc:mysql://" + config.getMysqlUrl() + ":" + config.getMysqlPort() + "/" + config.getMysqlDatabaseName() + "?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai", config.getMysqlAccountName(), config.getMysqlAccountPassword());
            List<ModelInfo> modelInfoList = getModelInfoList(connection, config.getPackageName());
            startGenerate(connection, createTemplateList(cfg), modelInfoList, config.getFilePath());
            MysqlUtil.closeConnection(connection);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    private static List<Template> createTemplateList(Configuration cfg) {
        try {
            List<Template> templateList = new ArrayList<>();
            Template modelTemplate = cfg.getTemplate("Model.java.ftl");
            Template mapperJavaTemplate = cfg.getTemplate("Mapper.java.ftl");
            Template mapperXmlTemplate = cfg.getTemplate("Mapper.xml.ftl");
            Template serviceTemplate = cfg.getTemplate("Service.java.ftl");
            Template serviceImplTemplate = cfg.getTemplate("ServiceImpl.java.ftl");
            Template controllerTemplate = cfg.getTemplate("Controller.java.ftl");
            templateList.add(modelTemplate);
            templateList.add(mapperJavaTemplate);
            templateList.add(mapperXmlTemplate);
            templateList.add(serviceTemplate);
            templateList.add(serviceImplTemplate);
            templateList.add(controllerTemplate);
            return templateList;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    private static List<ModelInfo> getModelInfoList(Connection connection, String packageName) {
        List<ModelInfo> modelInfoList = new ArrayList<>();
        try {
            DatabaseMetaData metaData = connection.getMetaData();
            ResultSet tables = metaData.getTables(connection.getCatalog(), null, null, null);

            while (tables.next()) {
                ModelInfo modelInfo = new ModelInfo();
                modelInfo.setPackageName(packageName);
                String tableName = tables.getString("TABLE_NAME");
                String remarks = tables.getString("REMARKS");
                String modelName = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, tableName);
                modelInfo.setTableName(tableName);
                modelInfo.setModelName(modelName);
                modelInfo.setControllerName(modelName + "Controller");
                modelInfo.setMapperName(modelName + "Mapper");
                modelInfo.setServiceName(modelName + "Service");
                modelInfo.setRemarks(remarks);
                modelInfoList.add(modelInfo);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return modelInfoList;
    }

    private static void startGenerate(Connection connection, List<Template> templateList, List<ModelInfo> modelInfoList, String filePath) throws Exception {
        if (modelInfoList.size() > 0) {
            DatabaseMetaData metaData = connection.getMetaData();
            for (ModelInfo modelInfo : modelInfoList) {
                ResultSet columns = metaData.getColumns(connection.getCatalog(), null, modelInfo.getTableName(), null);
                ResultSet primaryKeys = metaData.getPrimaryKeys(connection.getCatalog(), null, modelInfo.getTableName());
                List<ColumnClass> columnClassList = new ArrayList<>();
                while (columns.next()) {
                    String columnName = columns.getString("COLUMN_NAME");
                    String typeName = columns.getString("TYPE_NAME");
                    String remarks = columns.getString("REMARKS");
                    ColumnClass columnClass = new ColumnClass();
                    columnClass.setRemark(remarks);
                    columnClass.setColumnName(columnName);
                    columnClass.setType(typeName);
                    columnClass.setPropertyName(CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, columnName));
                    primaryKeys.first();
                    while (primaryKeys.next()) {
                        String pkName = primaryKeys.getString("COLUMN_NAME");
                        if (columnName.equals(pkName)) {
                            columnClass.setPrimary(true);
                        }
                    }
                    columnClassList.add(columnClass);
                }
                modelInfo.setColumns(columnClassList);
                startGenerate(templateList.get(0), modelInfo, filePath + modelInfo.getModelName());
                startGenerate(templateList.get(1), modelInfo, filePath + modelInfo.getModelName());
                startGenerate(templateList.get(2), modelInfo, filePath + modelInfo.getModelName());
                startGenerate(templateList.get(3), modelInfo, filePath + modelInfo.getModelName());
                startGenerate(templateList.get(4), modelInfo, filePath + modelInfo.getModelName());
                startGenerate(templateList.get(5), modelInfo, filePath + modelInfo.getModelName());
            }
        }
    }

    private static void startGenerate(Template template, ModelInfo modelInfo, String path) throws IOException, TemplateException {
        File folder = new File(path);
        if (!folder.exists()) {
            folder.mkdirs();
        }
        String fileName = path + "/" + modelInfo.getModelName() + template.getName().replace(".ftl", "").replace("Model", "");
        FileOutputStream fos = new FileOutputStream(fileName);
        OutputStreamWriter out = new OutputStreamWriter(fos);
        template.process(modelInfo, out);
        fos.close();
        out.close();
    }
}
